const fs = require('fs');
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const extend = require('extend');
const mime = require('mime');
const rimraf = require('rimraf');

const loadToBase64 = path => {
    if (/^https?:\/\//.test(path)) {
        return path;
    } else {
        let mimeType = mime.lookup(path);
        return 'data:' + (mimeType ? mimeType + ';' : '') + 'base64,' + Buffer.from(fs.readFileSync(path)).toString('base64');
    }
};

const asDefine = value => {
    if (typeof value === 'undefined') {
        return value;
    } else if (typeof value === 'object') {
        if (Array.isArray(value)) {
            return value.map(v => asDefine(v));
        } else {
            let result = { };
            for (let name in value) {
                if (value.hasOwnProperty(name)) {
                    result[name] = asDefine(value[name]);
                }
            }
            return result;
        }
    } else {
        return JSON.stringify(value);
    }
};

const extensions = {
    css: {
        less: [ '.less' ]
    },
    mvvm: {
        vue: [ '.vue' ]
    }
};
const externals = {
    vue: {
        vue: 'Vue'
    }
};

const loaders = {
    css: {
        less() {
            return [
                {
                    test: /\.less$/,
                    loader: 'style-loader!css-loader!less-loader',
                    exclude: {
                        and: [
                            /node_modules|bower_components/,
                            { not: [ /board-game/ ] }
                        ]
                    }
                }
            ]
        }
    },
    mvvm: {
        vue(config) {
            const cssLoaders = {
                less() {
                    return {
                        less: 'vue-style-loader!css-loader!less-loader'
                    };
                }
            };
            return [
                {
                    test: [ require.resolve('./web/vue/adapter'), require.resolve('./web/vue/mixin') ],
                    loader: 'babel-loader',
                    options: { presets: config.presets }
                },
                {
                    test: /\.vue$/,
                    loader: 'vue-loader',
                    options: {
                        loaders: extend(true, {
                            js: {
                                loader: 'babel-loader',
                                options: {
                                    presets: config.presets
                                }
                            }
                        }, cssLoaders[config.css] && cssLoaders[config.css](config) || { })
                    },
                    exclude: {
                        and: [
                            /node_modules|bower_components/,
                            { not: [ /board-game/ ] }
                        ]
                    }
                }
            ]
        }
    }
};


module.exports = (config, callback) => {
    if (fs.existsSync(path.resolve(config.assets))) {
        rimraf.sync(path.resolve(config.assets));
    }
    fs.mkdirSync(path.resolve(config.assets));
    webpack({
        entry: {
            index: config.index
        },
        output: {
            path: path.resolve(config.assets),
            filename: config.hash ? '[name].[hash].js' : '[name].js'
        },
        module: {
            loaders: [
                {
                    test: /\.js$/,
                    loader: 'babel-loader',
                    options: {
                        presets: config.presets
                    },
                    // exclude: /node_modules|bower_components/
                    exclude: {
                        and: [
                            /node_modules|bower_components/,
                            { not: [ /board-game/ ] }
                        ]
                    }
                },
                {
                    test: require.resolve('./client'),
                    use: [
                        {
                            loader: 'babel-loader',
                            options: {
                                presets: config.presets
                            }
                        },
                        {
                            loader: `imports-loader?css=./css/${ config.css }/client.${ config.css }&adapter=./web/${ config.mvvm }/adapter`
                        }
                    ],
                },
                {
                    test: /\.css$/,
                    loader: 'style-loader!css-loader',
                },
                {
                    test: /\.(png|jpe?g|gif|ico|wav|mp[34]|ogg)$/,
                    loader: 'url-loader?limit=10000&name=[name].[ext]'
                },
                {
                    test: /\.woff2?(\?.*)?$/,
                    loader: 'url-loader?limit=10000&name=[name].[ext]&mimetype=application/font-woff'
                },
                {
                    test: /\.ttf(\?.*)?$/,
                    loader: 'url-loader?limit=10000&name=[name].[ext]&mimetype=application/octet-stream'
                },
                {
                    test: /\.eot(\?.*)?$/,
                    loader: 'url-loader?limit=10000&name=[name].[ext]'
                },
                {
                    test: /\.svg(\?.*)?$/,
                    loader: 'url-loader?limit=10000&name=[name].[ext]&mimetype=image/svg+xml'
                }
            ]
                .concat(loaders.css[config.css] && loaders.css[config.css](config) || [])
                .concat(loaders.mvvm[config.mvvm] && loaders.mvvm[config.mvvm](config) || [])
                .concat(config.loaders || [])
        },
        resolve: {
            extensions: ['.js', '.json'].concat(extensions.css[config.css] || []).concat(extensions.mvvm[config.mvvm] || [])
        },
        resolveLoader: {
            modules: [path.join(__dirname, 'node_modules'), 'node_modules']
        },
        externals: extend(true, {
            jquery: 'jQuery',
            'socket.io-client': 'io',
            qrcode: 'qrcode',
        }, externals[config.mvvm] || { }),
        plugins: [
            new HtmlWebpackPlugin({
                filename: 'entry.html',
                title: config.name,
                meta: {
                    description: config.description || config.name,
                    keywords: config.keywords || config.name
                },
                inject: 'head',
                template: path.join(__dirname, 'index.ejs'),
                body: fs.readFileSync(path.join(__dirname, `web/${ config.mvvm }/index.html`)),
                logo: config.logo ? loadToBase64(config.logo) : false
            }),
            new HtmlWebpackPlugin({
                filename: 'seo.html',
                seo: true,
                title: config.name,
                meta: {
                    description: config.description || config.name,
                    keywords: config.keywords || config.name
                },
                inject: 'head',
                template: path.join(__dirname, 'index.ejs'),
                logo: config.logo ? loadToBase64(config.logo) : false
            }),
            new webpack.DefinePlugin({ config: extend(true, asDefine(config), { dev: process.env.NODE_ENV === 'development' }) })
        ].concat(config.compress ? [
            new webpack.optimize.UglifyJsPlugin({
                compress: {
                    warnings: false,
                    drop_debugger: true,
                    drop_console: true,
                    properties: true,
                    join_vars: true
                }
            })
        ] : []),
        watch: config.watch,
        devtool: config.devtool
    }, (err, stats) => {
        process.stdout.write(stats.toString(config.stats) + "\n");
        if(err) console.error(err);
        else callback && callback();
    });
};